<!DOCTYPE html>

<html lang="en">
<head>
<title>Web VR boilerplate</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<style>
body {
  width: 100%;
  height: 100%;
  background-color: #000;
  color: #fff;
  margin: 0px;
  padding: 0;
  overflow: hidden;
}
</style>
</head>

<body>

</body>

<script>
/*
 * Debug parameters.
 */
WebVRConfig = {
  /**
   * webvr-polyfill configuration
   */

  // Forces availability of VR mode.
  //FORCE_ENABLE_VR: true, // Default: false.
  // Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
  // K_FILTER: 0.5, // Default: 0.98.
  // How far into the future to predict during fast motion.
  PREDICTION_TIME_S: 0.020, // Default: 0.040 (in seconds).
  // Flag to disable touch panner. In case you have your own touch controls
  //TOUCH_PANNER_DISABLED: true, // Default: false.
  // Enable yaw panning only, disabling roll and pitch. This can be useful for
  // panoramas with nothing interesting above or below.
  //YAW_ONLY: true, // Default: false.
  // Enable the deprecated version of the API (navigator.getVRDevices).
  //ENABLE_DEPRECATED_API: true, // Default: false.
  // Scales the recommended buffer size reported by WebVR, which can improve
  // performance. Making this very small can lower the effective resolution of
  // your scene.
  BUFFER_SCALE: 2.0, // default: 1.0
  // Allow VRDisplay.submitFrame to change gl bindings, which is more
  // efficient if the application code will re-bind it's resources on the
  // next frame anyway.
  // Dirty bindings include: gl.FRAMEBUFFER_BINDING, gl.CURRENT_PROGRAM,
  // gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING,
  // and gl.TEXTURE_BINDING_2D for texture unit 0
  // Warning: enabling this might lead to rendering issues.
  //DIRTY_SUBMIT_FRAME_BINDINGS: true // default: false
};
</script>

<!--
  A polyfill for Promises. Needed for IE and Edge.
  -->
<!-- <script src="node_modules/es6-promise/dist/es6-promise.js"></script> -->

<!--
  three.js 3d library
  -->
<script src="src/three.min.js"></script>

<script src="src/stats.min.js"></script>

<script src="src/extra/Animation.js"></script>
<script src="src/extra/AnimationHandler.js"></script>
<script src="src/extra/KeyFrameAnimation.js"></script>

<script src="src/extra/ColladaLoader.js"></script>

<!-- <script src="src/extra/Detector.js"></script> -->
<script src="src/extra/dat.gui.min.js"></script>

<!--
  VRControls.js acquires positional information from connected VR devices and applies the transformations to a three.js camera object.
   -->
<script src="node_modules/three/examples/js/controls/VRControls.js"></script>

<!--
  VREffect.js handles stereo camera setup and rendering.
  -->
<script src="node_modules/three/examples/js/effects/VREffect.js"></script>

<!--
  A polyfill for WebVR using the Device{Motion,Orientation}Event API.
  -->
<script src="node_modules/webvr-polyfill/build/webvr-polyfill.js"></script>

<!--
  Helps enter and exit VR mode, provides best practices while in VR.
  -->
<script src="build/webvr-manager.js"></script>

<script src="src/jquery-3.1.1.min.js"></script>

<video id="video" autoplay="true" loop="false" hidden="hidden" src="vr_style_s.mp4" muted webkit-playsinline >
</video>
<video id="video_content" hidden="hidden" src="dd.mp4" autoplay="true" loop="false"  webkit-playsinline >
</video>
<video id="video2" hidden="hidden" webkit-playsinline>
</video>
<script type="x-shader/x-vertex" id="vertexShader">
      uniform sampler2D uSampler;

      varying mediump vec4 vDirection;

      void main() {
        vec4 outExtraPixel =  projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        
        gl_Position = outExtraPixel;
        
        vDirection = vec4( position, 1.0 );
      }

</script>

<script type="x-shader/x-fragment" id="fragmentShader">
      precision mediump float;
      #define PI 3.1415926535897932384626433832795


      uniform sampler2D uSampler;
      uniform sampler2D uSource;

      uniform float uRotate;
      uniform float uTop;
      uniform float uScale;

      uniform float uDiff;

      varying mediump vec4 vDirection;

      mediump vec4 samplerColor(mediump vec3 direction){
        mediump float theta = atan(direction.x, -1.0 * direction.z);
        mediump float phi = atan(direction.y, length(direction.xz));
        if (abs(direction.x) < 1e-4 * abs(direction.z))
          theta = 0.5*PI * (1.0 - sign(-1.0 * direction.z));
        if (abs(direction.y) < 1e-4 * length(direction.xz))
          phi = 0.0;

        float radio = 9.5 / 3.5 ;
        float base = uScale;
        float left = 3.;
        float top = uTop;
        float dy = (phi / PI + 0.5)*base-top;
        if(dy >1.||dy < 0.){
          return vec4(0.,1.,0.,1.);
        }
        float dx=(mod(theta / (2.0*PI), 1.0))*base*radio-left;
        if(dx >1. || dx < 0.){
          return vec4(0.,1.,0.,1.);
        }
        return texture2D(uSampler,vec2(dx,dy));
      }
      mediump vec4 sourceColor(mediump vec3 direction){

        mediump float theta = atan(direction.x, -1.0 * direction.z);
        mediump float phi = atan(direction.y, length(direction.xz));

        if (abs(direction.x) < 1e-4 * abs(direction.z))
        theta = 0.5*PI * (1.0 - sign(-1.0 * direction.z));
        if (abs(direction.y) < 1e-4 * length(direction.xz))
        phi = 0.0;
        float dx=mod(theta / (2.0*PI), 1.0);
        float dy=phi / PI + 0.5;
        dx+=uRotate;
        if(dx>1.){
          dx-=1.;
        }

        return texture2D(uSource,vec2(dx,dy));
      }

      void main() {
        mediump vec3 direction =  vec3(vDirection.xyz/vDirection.w);

        float diff=uDiff;
        float left=.45;

        vec4 sourcePixel = sourceColor(direction);

        vec4 extraPixel = samplerColor(direction);
        vec4 outExtraPixel =extraPixel;
        if(vDirection.x+left<0.){
          outExtraPixel = sourcePixel;
        }
        if (extraPixel.g > 0.50 && extraPixel.r < 0.5 && extraPixel.b <0.5){
          outExtraPixel = sourcePixel;
        }else if(extraPixel.g>0.7&&extraPixel.r > 0.4 && extraPixel.r <0.65 && extraPixel.b>0.4&&extraPixel.b<0.65){
          outExtraPixel = sourcePixel;
        }else if(extraPixel.g>0.9&& extraPixel.r<0.1 &&extraPixel.b<0.1){
          outExtraPixel = sourcePixel;
        }else if((extraPixel.g/extraPixel.r)>diff&&(extraPixel.g/extraPixel.b)>diff){
          outExtraPixel = sourcePixel;
        }else if(extraPixel.r == 0.0 && extraPixel.g == 0.0 && extraPixel.b == 0.0){
          outExtraPixel = sourcePixel;
        }
        gl_FragColor= outExtraPixel;
      }

</script>
<script>
// Setup three.js WebGL renderer. Note: Antialiasing is a big performance hit.
// Only enable it if you actually need to.
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);

// Append the canvas element created by the renderer to document body element.
document.body.appendChild(renderer.domElement);

// Create a three.js scene.
var scene = new THREE.Scene();

// Create a three.js camera.
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);

// Apply VR headset positional data to camera.
var controls = new THREE.VRControls(camera);
controls.standing = true;

// Apply VR stereo rendering to renderer.
var effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);

// Add a repeating grid as a skybox.
var boxSize = 1;

video = document.getElementById( 'video' );

texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;


function getCubeBox(){
  var geometry = new THREE.CubeGeometry(20,20,20);

  // cubeFaceVertexUvs
  var originUv=[[new THREE.Vector2( 1, 1.0/2),new THREE.Vector2( 1,0),new THREE.Vector2(2.0/3, 1.0/2)],[new THREE.Vector2( 1, 0),new THREE.Vector2(2.0/3,0),new THREE.Vector2(2.0/3, 1.0/2)]];
  var originUvs=[];
  for(var i=0;i<12;i++){
    var tUv=[];
    var dx=(parseInt(i/2)%3)*1.0/3;
    var dy=parseInt(i/6)*1.0/2;
    var index=(i+1)%2;
    tUv[0] = new THREE.Vector2(originUv[index][0].x-dx, originUv[index][0].y+dy);
    tUv[1] = new THREE.Vector2(originUv[index][1].x-dx, originUv[index][1].y+dy);
    tUv[2] = new THREE.Vector2(originUv[index][2].x-dx, originUv[index][2].y+dy);

    originUvs.push(tUv);
  }

  //* Place cubemap video faces in right places
  for(var i=0;i<12;i++){
    geometry.faceVertexUvs[0][11-i]=originUvs[i];
  }
  var temp1=geometry.faceVertexUvs[0][0];
  var temp2=geometry.faceVertexUvs[0][1];
  geometry.faceVertexUvs[0][0]=geometry.faceVertexUvs[0][2];
  geometry.faceVertexUvs[0][1]=geometry.faceVertexUvs[0][3];
  geometry.faceVertexUvs[0][2]=temp1;
  geometry.faceVertexUvs[0][3]=temp2;

  //* Cubemap video faces are expanded 1.01 by ffmpeg transform,fix them here.
  var fixP=0.0018;
  for(var i=0;i<12;i+=2){
    geometry.faceVertexUvs[0][i][0].y-=fixP;
    geometry.faceVertexUvs[0][i][2].y-=fixP;
    geometry.faceVertexUvs[0][i][0].x-=fixP;
    geometry.faceVertexUvs[0][i][1].x-=fixP;

    geometry.faceVertexUvs[0][i][1].y+=fixP;
    geometry.faceVertexUvs[0][i][2].x+=fixP;

    geometry.faceVertexUvs[0][i+1][0].y+=fixP;
    geometry.faceVertexUvs[0][i+1][1].y+=fixP;
    geometry.faceVertexUvs[0][i+1][1].x+=fixP;
    geometry.faceVertexUvs[0][i+1][2].x+=fixP;

    geometry.faceVertexUvs[0][i+1][0].x-=fixP;
    geometry.faceVertexUvs[0][i+1][2].y-=fixP;
  }
  var cubebox = new THREE.Mesh(geometry, material);
  cubebox.position.y = 1.5;
  cubebox.position.x = 0;
  cubebox.rotation.y = 2*Math.PI;
  return cubebox;
}

var material = new THREE.MeshBasicMaterial({
  map: texture,
  side: THREE.BackSide
});

// For high end VR devices like Vive and Oculus, take into account the stage
// parameters provided.
setupStage();

var plane_position=0;

function addPlane(item) {

  var img=item.pictures.img;
  img=img.replace('http:/','/u');
  var texture = new THREE.TextureLoader().load(img);
  texture.wrapS = THREE.ClampToEdgeWrapping;
  texture.wrapT = THREE.ClampToEdgeWrapping;
  var radio=1.5;
  var planeWidth=0.4*radio;
  var planeHeight=0.3*radio;
  var planeSpan=0.05*radio;
  var geometry = new THREE.PlaneGeometry(planeWidth,planeHeight);
  
  var material =new THREE.MeshBasicMaterial({
    map: texture,
    color: 0xffffff,
    side: THREE.BackSide
  });
 
  var plane = new THREE.Mesh( geometry, material);
  plane.name="plane_"+plane_position;
  plane.data=item;
  plane.position.set(1.5, controls.userHeight-0.5, 0.5);
  plane.position.y+=(plane_position%4)*(planeHeight+planeSpan);
  plane.position.z=parseInt(plane_position/4)*(planeWidth+planeSpan);
  plane_position+=1;
  plane.rotation.y=Math.PI/2;
  scene.add(plane);

  if(!playing){
    playing=true;
    playRoom(item);
  }
}
var liveItems;
function getPlanesData(){
  var url="/u/api.m.panda.tv/ajax_get_live_list_by_cate?cate=dota2&pageno=0&pagenum=12&__plat=h5";
  $.getJSON(url,'',function(json){
    var items=json.data.items;
    liveItems=items;
    for(var i=0;i<items.length;i++){
      var item=items[i];
      addPlane(item);
    }
  });
}
// getPlanesData();

// monster (front animation)
var clock = new THREE.Clock();
var dae;
var mixer;
var dae_x=4.09;
var dae_y=-1.42;
mixer = new THREE.AnimationMixer( scene );
function addMonster(){
  var loader = new THREE.ColladaLoader();
      loader.options.convertUpAxis = true;
      loader.load( 'models/monster.dae', function ( collada ) {
        dae = collada.scene;
        dae.traverse( function ( child ) {
          if ( child instanceof THREE.SkinnedMesh ) {
            var animation = new THREE.Animation( child, child.geometry.animation );
            animation.play();
          }
        } );
        dae.scale.x = dae.scale.y = dae.scale.z = 0.001;
        dae.position.x = dae_x;
        dae.position.y = dae_y;
        dae.position.z = -2;
        dae.rotation.y= 1 * Math.PI;
        dae.updateMatrix();
        scene.add( dae );
        scene.add( new THREE.AmbientLight( 0xffffff ) );
      } );
}
addMonster();

var logo_text;
var logo;
function addAppgameLogo(text){
  var loader = new THREE.FontLoader();
      loader.load( 'models/appgame.typeface.json', function ( font ) {
        text=text.replace(/[^任玩堂游戏手机好超级知道你我他]/g,'');
        var logo_text = new THREE.TextGeometry( text, {
          font: font,
          size: 0.1,
          height:0.01
        } );
        if(logo){
          scene.remove(logo);
          logo.geometry.dispose();

        }
        logo=new THREE.Mesh(logo_text,new THREE.MeshBasicMaterial());
        logo.position.set(0, controls.userHeight, 0);
        logo.position.z-=2;
        scene.add(logo);

      } );
}
$(function(){
  addAppgameLogo('任玩堂');
});

// Chromakey content
var video_content;
var texture_content;
var v_texture;
var v_shaderMaterial;
var effectController = {
    bg_rotate: 0.,//background rotate
    c_top: 0.79,//content top
    c_scale: 3.53,
    monster_left:dae_x,
    monster_top:dae_y,
    video:'vr_style_s',
    text:'任玩堂',
    c_diff:1.11,
    cubemapMode:false,
    'bg_play/pause':function(){
      if(video.paused){
        video.play();
      }else{
        video.pause();
      }
    },
    'stream_panda':function(){
      video_content.muted=true;
      getPlanesData();
    }
  };
var changeCube=false;

function getContentVideo(){
  var contentBox;
  video_content = document.getElementById( 'video_content' );
  texture_content = new THREE.VideoTexture( video_content );
  texture_content.minFilter = THREE.LinearFilter;
  texture_content.magFilter = THREE.LinearFilter;

  var geometry = new THREE.SphereBufferGeometry( 50, 32, 32);
  
  v_shaderMaterial = new THREE.ShaderMaterial( {
          uniforms: {
            'uSampler':{
              value:texture_content
            },
            'uSource':{
              value:texture
            },
            'uRotate':{
              value:effectController.bg_rotate
            },
            'uTop':{
              value:effectController.c_top
            },
            'uScale':{
              value:effectController.c_scale
            },
            'uDiff':{
              value:effectController.c_diff
            }
          },
          vertexShader: document.getElementById( 'vertexShader' ).textContent,
          fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
          side: THREE.DoubleSide
  } );

  v_shaderMaterial.extensions.derivatives = true;

  contentBox = new THREE.Mesh( geometry, v_shaderMaterial);

  contentBox.position.set(0, controls.userHeight, 0);
  contentBox.rotation.y=0.6*Math.PI;
  video_content.play();
  return contentBox;
}


function setupGui(){
  var gui = new dat.GUI();
  
  var valuesChanger = function() {
    // velocityUniforms.seperationDistance.value = effectController.seperation;
    // velocityUniforms.alignmentDistance.value = effectController.alignment;
    // velocityUniforms.cohesionDistance.value = effectController.cohesion;
    // velocityUniforms.freedomFactor.value = effectController.freedom;
    if(v_shaderMaterial){
      v_shaderMaterial.uniforms.uRotate.value=effectController.bg_rotate;
      v_shaderMaterial.uniforms.uTop.value=effectController.c_top;
      v_shaderMaterial.uniforms.uScale.value=effectController.c_scale;
      v_shaderMaterial.uniforms.uDiff.value=effectController.c_diff;
      dae_x=effectController.monster_left;
      dae_y=effectController.monster_top;
      $(video).attr('src',effectController.video+'.mp4');
      addAppgameLogo(effectController.text);
      if(changeCube!=effectController.cubemapMode){
        if(effectController.cubemapMode){
          scene.remove(skybox);
          skybox = getCubeBox();
          scene.add(skybox);
        }else{
          scene.remove(skybox);
          skybox = getContentVideo();
          scene.add(skybox);
        }
        changeCube = effectController.cubemapMode;
      }
    }
    
  };
  valuesChanger();
  gui.add( effectController, "bg_rotate", 0.0, 1.0, 0.01).onChange( valuesChanger );
  gui.add( effectController, "c_diff", 0.0, 2.0, 0.01).onChange( valuesChanger );
  gui.add( effectController, "c_top", -1.0, 10.0, 0.01 ).onChange( valuesChanger );
  gui.add( effectController, "c_scale", 0.1, 10, 0.01 ).onChange( valuesChanger );
  gui.add( effectController, "monster_left", -10, 10, 0.01 ).onChange( valuesChanger );
  gui.add( effectController, "monster_top", -5, 5, 0.01 ).onChange( valuesChanger );
  gui.add( effectController, "video", ['vr_style_s','100m','lol'] ).onChange( valuesChanger );
  gui.add( effectController, "cubemapMode").onChange( valuesChanger );
  gui.add( effectController, "text").onChange( valuesChanger );
  gui.add( effectController, "bg_play/pause");
  gui.add( effectController, "stream_panda");
  

  $(gui.domElement).on('touchstart,touchend,touchmove',function(event){
    console.log(event)
    event.stopPropagation();
  });
  // $(gui.domElement).on('mousemove',function(event){
  //   event.stopPropagation();
  // });
  // gui.close();
}
$(setupGui);
skybox = getContentVideo();
scene.add(skybox);


var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

var select=false;
var playing=false;

function onMouseUp( event ) {

  // calculate mouse position in normalized device coordinates
  // (-1 to +1) for both components

  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

  select=true;
}

window.addEventListener( 'mouseup', onMouseUp, false );

// Create a VR manager helper to enter and exit VR mode.
var params = {
  hideButton: false, // Default: false.
  isUndistorted: false // Default: false.
};
var manager = new WebVRManager(renderer, effect, params);


// Kick off animation loop
requestAnimationFrame(animate);

window.addEventListener('resize', onResize, true);
window.addEventListener('vrdisplaypresentchange', onResize, true);

// Request animation frame loop function
var lastRender = 0;
function animate(timestamp) {
  var delta = Math.min(timestamp - lastRender, 500);
  lastRender = timestamp;

  // Update VR headset position and apply to camera.
  controls.update();

  // dae_x-=0.01;
  if(dae){
    dae.position.x = dae_x;
    dae.position.y = dae_y;
  }

  // update the picking ray with the camera and mouse position  
  raycaster.setFromCamera( mouse, camera ); 

 // calculate objects intersecting the picking ray
  var intersects = raycaster.intersectObjects( scene.children );

  if(select){
    select=false;
    for ( var i = 0; i < intersects.length; i++ ) {
      var object=intersects[ i ].object;
      if(object.data){
        playRoom(object.data);
      }
    }
  }

  var delta = clock.getDelta();
  // animate Collada model
  THREE.AnimationHandler.update( delta );
  mixer.update( delta );
  // Render the scene through the manager.
  manager.render(scene, camera, timestamp);

  requestAnimationFrame(animate);
}

function onResize(e) {
  effect.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
}

var display;

// Get the HMD, and if we're dealing with something that specifies
// stageParameters, rearrange the scene.
function setupStage() {
  // navigator.getVRDisplays().then(function(displays) {
  //   if (displays.length > 0) {
  //     display = displays[0];
  //     if (display.stageParameters) {
  //       setStageDimensions(display.stageParameters);
  //     }
  //   }
  // });
}

function setStageDimensions(stage) {
  // Make the skybox fit the stage.
  var material = skybox.material;
  scene.remove(skybox);

  // Size the skybox according to the size of the actual stage.
  var geometry = new THREE.BoxGeometry(stage.sizeX, boxSize, stage.sizeZ);
  skybox = new THREE.Mesh(geometry, material);

  // Place it on the floor.
  skybox.position.y = boxSize/2;
  scene.add(skybox);

}

//show fps
// var stats = new Stats();
// stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
// document.body.appendChild( stats.dom );

// function fps() {

//     stats.begin();

//     // monitored code goes here

//     stats.end();

//     requestAnimationFrame( fps );

// }

// requestAnimationFrame( fps );

function playRoom(room){
  console.log(room);
  var url="/u/room.api.m.panda.tv/index.php?method=room.shareapi&roomid="+room.id;
  $.getJSON(url,'',function(json){
    var urlVideo=json.data.videoinfo.address;
    urlVideo=urlVideo.replace('http:/','/u');
    VRhls.loadSource(urlVideo);
    VRhls.attachMedia(video2);
  });
}

</script>

<script src="src/hls.min.js"></script>
<script>
var VRhls;
if (Hls.isSupported()) {
    function playVideo(video){
      var texture = new THREE.VideoTexture( video );
      texture.minFilter = THREE.LinearFilter;
      texture.magFilter = THREE.LinearFilter;
      texture.format = THREE.RGBFormat;

      texture.wrapS = THREE.ClampToEdgeWrapping;
      texture.wrapT = THREE.ClampToEdgeWrapping;

      var geometry = new THREE.PlaneGeometry(3, 1.8);
      var material = new THREE.MeshBasicMaterial({
        map: texture,
        color: 0xffffff,
        side: THREE.DoubleSide
      });
      var videoPlane=new THREE.Mesh(geometry, material);
      videoPlane.position.set(0, controls.userHeight, -1.5);
      videoPlane.position.x=0;
      scene.add(videoPlane);
    }
    var video2 = document.getElementById('video2');
    var hls = new Hls();
    var VRhls=hls;
    hls.attachMedia(video2);
    hls.on(Hls.Events.MANIFEST_PARSED, function() {
        // video2.play();
        playVideo(video2);
    });
}

$(renderer.domElement).on('click',function(){
  video.play();
  video2.play();
  video_content.play();
});
</script>

</html>
